/**
 * Copyright (c) 2009 Moogene
 * All rights reserved
 *
 * This software is the confidential and proprietary information of Moogene.
 * You shall not disclose such Confidential Information and shall use it only
 * in accordance with the terms of the license agreement you entered into
 * with Moogene
 */

package com.moogene.android.engine.action;

import java.util.concurrent.ArrayBlockingQueue;

import android.view.MotionEvent;

import com.moogene.android.engine.util.MooMath;

/**
 * @author Song, jiawei
 */
public class ActTouchEvent {
    public final static int TYPE_INVALID = -1;

    public final static int TYPE_PRESS = 4;

    public final static int TYPE_HOLD = 5;

    public final static int TYPE_REALEASE = 6;

    public final static int EVOLVE_TYPE_MOVE = 7;

    public final static int EVOLVE_TYPE_CLICK = 8;

    public final static int EVOLVE_TYPE_DOUBLE_CLICK = 9;

    public final static int EVOLVE_TYPE_SLIDE_SHORT = 10;

    public final static int EVOLVE_TYPE_SLIDE_LONG = 11;

    private int mType;

    private int mEvolveType;

    private int mX;

    private int mY;

    private int mLastX;

    private int mLastY;

    private double mSlideDir;

    private int mSlideSpeed;

    private int mSlideOffX;

    private int mSlideOffY;

    // private int mSlideStartX;
    // private int mSlideStartY;
    // private int mSlideEndX;
    // private int mSlideEndY;
    private ArrayBlockingQueue<Integer> mStoredPos;

    private static int mHoldTick;

    private final static int CLICK_TICK_INVALID = -1;

    private final static int CLICK_TICK_START = 0;

    private static int mDoubleClickTick;

    private static ActTouchEvent sActTouchEvent;

    private TouchAnalyse mTouchAnalyse;

    private ActTouchEvent() {
        mTouchAnalyse = TouchAnalyse.getInstance();
        mStoredPos = new ArrayBlockingQueue<Integer>(Config.GESTURE_STORE_POS_CAPACITY << 1);
    }

    public static ActTouchEvent getInstance() {
        if (sActTouchEvent == null) {
            sActTouchEvent = new ActTouchEvent();
        }
        return sActTouchEvent;
    }

    public void setup(MotionEvent me) {
        switch (me.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mType = TYPE_PRESS;
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                mType = TYPE_REALEASE;
                break;
            case MotionEvent.ACTION_MOVE:
                mType = TYPE_HOLD;
                break;
        }
        int x = (int)me.getX();
        int y = (int)me.getY();

        mX = x;
        mY = y;

        if (Config.TOUCH_EXTEND_SUPPORT) {
            if (mDoubleClickTick >= CLICK_TICK_START) {
                mDoubleClickTick++;
            }
            mEvolveType = TYPE_INVALID;
            mLastX = mX;
            mLastY = mY;
            switch (mType) {
                case TYPE_PRESS:
                    ActionManager.log("Touch New Press Detected");
                    break;
                case TYPE_HOLD:
                    mHoldTick++;
                    ActionManager.log("Touch Hold Detected, Hold Tick: "
                            + mHoldTick);
                    if (mStoredPos.size() >= 2) {
                        if (isMoveDis(x
                                - mLastX, y
                                - mLastY)) {
                            mEvolveType = EVOLVE_TYPE_MOVE;
                            mDoubleClickTick = CLICK_TICK_INVALID;
                            mSlideOffX = x
                                    - mLastX;
                            mSlideOffY = y
                                    - mLastX;
                            ActionManager.log("Touch Gesture Move Detected; offX:"
                                    + mSlideOffX
                                    + " offY:"
                                    + mSlideOffY);
                        } else {
                            mSlideOffX = 0;
                            mSlideOffY = 0;
                            // mStoredPos.clear();
                            ActionManager.log("Touch Gesture Move Stopped");
                        }
                        if (mStoredPos.size() + 1 >= Config.GESTURE_STORE_POS_CAPACITY << 1) {
                            mStoredPos.poll();
                            mStoredPos.poll();
                        }
                    }
                    mStoredPos.offer(x);
                    mStoredPos.offer(y);
                    break;

                case TYPE_REALEASE:
                    int size = mStoredPos.size();
                    if (mHoldTick > 0
                            && mHoldTick < Config.GESTURE_CLICK_TIME_GAP) {
                        if (mDoubleClickTick < Config.GESTURE_DOUBLE_CLICK_TIME_GAP) {
                            mEvolveType = EVOLVE_TYPE_DOUBLE_CLICK;
                            ActionManager.log("Touch Gesture Double Click Detected");
                        } else {
                            mEvolveType = EVOLVE_TYPE_CLICK;
                            mDoubleClickTick = CLICK_TICK_START;
                            ActionManager.log("Touch Gesture Click Detected");
                        }
                    } else if (size > Config.GESTURE_SLIDE_NUM_POS_MIN << 1) {
                        mSlideOffX = x
                                - mStoredPos.poll();
                        mSlideOffY = y
                                - mStoredPos.poll();
                        int dis = MooMath.fastDistance(mSlideOffX, mSlideOffY);
                        mSlideSpeed = dis
                                / mHoldTick;
                        if (size <= Config.GESTURE_SLIDE_NUM_POS_SHORT_MAX) {
                            mEvolveType = EVOLVE_TYPE_SLIDE_SHORT;
                        } else {
                            mEvolveType = EVOLVE_TYPE_SLIDE_LONG;
                        }
                        mDoubleClickTick = CLICK_TICK_INVALID;
                        ActionManager.log("Touch Gesture Slide Detected");
                    }

                    mHoldTick = 0;
                    mStoredPos.clear();
                    break;
            }
        }
    }

    public int getType() {
        return mType;
    }

    public int getEvolveType() {
        return mEvolveType;
    }

    public int getX() {
        return mX;
    }

    public int getY() {
        return mY;
    }

    public int getSlideOffX() {
        return mSlideOffX;
    }

    public int getSlideOffY() {
        return mSlideOffY;
    }

    private boolean isMoveDis(int dx, int dy) {
        boolean isMove = Math.abs(dx)
                + Math.abs(dy) > Config.GESTURE_SLIDE_DIS_MIN;
        ActionManager.log("Is Move Distance: "
                + isMove
                + " ; offX:"
                + dx
                + ", offY:"
                + dy);
        return isMove;
    }

}
